﻿using System.Text;
using System.Xml;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;

namespace Light.Utility.Security
{
    /// <summary>
    /// 加解密XML文件
    /// </summary>
    public class XMLCryptor
    {
        /// <summary>
        /// 加密xml文件 
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="rootNodeName">根节点名称</param>
        public static void EncryptFile(string fileName, string rootNodeName)
        {
            RijndaelManaged key = new RijndaelManaged();

            //设置密钥:key为32位=数字或字母16个=汉字8个
            byte[] byteKey = Encoding.Unicode.GetBytes("|de.cel@163.com|");
            key.Key = byteKey;
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.PreserveWhitespace = true;
            xmlDoc.Load(fileName);//加载要加密的XML文件
            encrypt(xmlDoc, rootNodeName, key);// DataBases为根节点
            if (key != null)
            {
                key.Clear();
            }
            xmlDoc.Save(fileName);//保存加密后的XML文件
        }

        /// <summary>
        /// 解密相应xml文件 
        /// </summary>
        /// <param name="fileName"></param>
        public static void DecryptFile(string fileName)
        {
            RijndaelManaged key = new RijndaelManaged();
            //设置密钥:key为32位=数字或字母16个=汉字8个
            byte[] byteKey = Encoding.Unicode.GetBytes("|de.cel@163.com|");
            key.Key = byteKey;
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.PreserveWhitespace = true;
            xmlDoc.Load(fileName);//加载要解密的XML文件
            decrypt(xmlDoc, key);
            if (key != null)
            {
                key.Clear();
            }
            xmlDoc.Save(fileName);//保存解密后的XML文件
        }

        /// <summary>
        /// xml加密方法
        /// </summary>
        /// <param name="Doc">xml文档</param>
        /// <param name="ElementName">节点名称</param>
        /// <param name="Key">对称算法</param>
        private static void encrypt(XmlDocument Doc, string ElementName, SymmetricAlgorithm Key)
        {
            XmlElement elementToEncrypt = Doc.GetElementsByTagName(ElementName)[0] as XmlElement;
            EncryptedXml eXml = new EncryptedXml();



            byte[] encryptedElement = eXml.EncryptData(elementToEncrypt, Key, false);
            EncryptedData edElement = new EncryptedData();
            edElement.Type = EncryptedXml.XmlEncElementUrl;
            string encryptionMethod = null;

            if (Key is TripleDES)
            {
                encryptionMethod = EncryptedXml.XmlEncTripleDESUrl;
            }
            else if (Key is DES)
            {
                encryptionMethod = EncryptedXml.XmlEncDESUrl;
            }
            if (Key is Rijndael)
            {
                switch (Key.KeySize)
                {
                    case 128:
                        encryptionMethod = EncryptedXml.XmlEncAES128Url;
                        break;
                    case 192:
                        encryptionMethod = EncryptedXml.XmlEncAES192Url;
                        break;
                    case 256:
                        encryptionMethod = EncryptedXml.XmlEncAES256Url;
                        break;
                }
            }
            edElement.EncryptionMethod = new EncryptionMethod(encryptionMethod);
            edElement.CipherData.CipherValue = encryptedElement;
            EncryptedXml.ReplaceElement(elementToEncrypt, edElement, false);
        }

        /// <summary>
        /// 解密算法
        /// </summary>
        /// <param name="Doc">xml文档</param>
        /// <param name="Alg">对称算法</param>
        private static void decrypt(XmlDocument Doc, SymmetricAlgorithm Alg)
        {
            XmlElement encryptedElement = Doc.GetElementsByTagName("EncryptedData")[0] as XmlElement;
            EncryptedData edElement = new EncryptedData();
            edElement.LoadXml(encryptedElement);
            EncryptedXml exml = new EncryptedXml();
            byte[] rgbOutput = exml.DecryptData(edElement, Alg);
            exml.ReplaceData(encryptedElement, rgbOutput);
        }

    }
}
